/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package algoritmogenetico;

import java.util.Random;

/**
 *
 * @author Jailton
 */
public class GAParaboloide {

    public static final int TAM_POPULACAO = 20;
    public static final int NUM_VARIAVEIS = 2;
    private double populacao[][] = new double[TAM_POPULACAO][NUM_VARIAVEIS];
    private double populacaoTemp[][] = new double[TAM_POPULACAO][NUM_VARIAVEIS];
    private int numeroIteracoes;
    private double limiteInf;
    private double limiteSup;

    public GAParaboloide(int numeroIteracoes, double limiteInf, double limiteSup) {
        this.numeroIteracoes = numeroIteracoes;
        this.limiteInf = limiteInf;
        this.limiteSup = limiteSup;

        geraPopulacaoInicial();
    }

    private void geraPopulacaoInicial() {
        Random random = new Random();
        for(int i = 0; i < TAM_POPULACAO; ++i) {
            for(int j = 0; j < NUM_VARIAVEIS; ++j) {
                populacao[i][j] = (limiteSup-limiteInf)*random.nextDouble() + limiteInf;
            }
        }

        bubbleSort();
    }

    private void bubbleSort() {
        for(int i = TAM_POPULACAO; i >= 1; --i) {
            for(int j = 1; j < i; ++j) {
                if(fitness(populacao[j-1]) > fitness(populacao[j])) {
                    swap(j-1, j);
                }
            }
        }
    }

    private void swap(int posicao1, int posicao2) {
        double auxX = populacao[posicao2][0];
        double auxY = populacao[posicao2][1];

        populacao[posicao2][0] = populacao[posicao1][0];
        populacao[posicao2][1] = populacao[posicao1][1];

        populacao[posicao1][0] = auxX;
        populacao[posicao1][1] = auxY;
    }

    public double fitness(double cromossomo[]) {
        return cromossomo[0]*cromossomo[0] + cromossomo[1]*cromossomo[1];
    }
        
    private int roletaRank() {
        Random random = new Random();

        int somaFitness = TAM_POPULACAO*(TAM_POPULACAO+1)/2;
        
        int pontoRoleta = random.nextInt(somaFitness);
        int i = 0, aux = 0;
        for(int j = TAM_POPULACAO; (i < TAM_POPULACAO-1) && (aux < pontoRoleta); ++i, --j) {
            aux += j;
        }
        
        return i;
    }

    public void crossover(int indexFilho1, int indexFilho2, int indexPai1, int indexPai2) {
        populacaoTemp[indexFilho1][0] = populacao[indexPai1][0];
        populacaoTemp[indexFilho1][1] = populacao[indexPai2][1];
        populacaoTemp[indexFilho2][0] = populacao[indexPai2][0];
        populacaoTemp[indexFilho2][1] = populacao[indexPai1][1];
    }

    public void mutacao(int indexPai, int indexFilho) {
        Random random = new Random();
        boolean escolheGene = random.nextBoolean();

        if(escolheGene) {
            populacaoTemp[indexFilho][0] = (limiteSup-limiteInf)*random.nextDouble() + limiteInf;
            populacaoTemp[indexFilho][1] = populacao[indexPai][1];
        }
        else {
            populacaoTemp[indexFilho][0] = populacao[indexPai][0];
            populacaoTemp[indexFilho][1] = (limiteSup-limiteInf)*random.nextDouble() + limiteInf;
        }
    }

    public void iteracao() {

        Random random = new Random();

        for(int i = 0; i < numeroIteracoes; ++i) {

            for(int j = 0; j < 2; ++j) {
                for(int k = 0; k < NUM_VARIAVEIS; ++k) {
                    populacaoTemp[j][k] = populacao[j][k];
                }
            }

            for(int j = 2; j < 12; j += 2) {
                int indexPai1 = roletaRank();
                int indexPai2;

                do {
                    indexPai2 = roletaRank();
                } while(indexPai1 == indexPai2);

                crossover(j, j+1, indexPai1, indexPai2);
            }

             for(int j = 12; j < 20; ++j) {
                 mutacao(random.nextInt(20), j);
             }

            for(int j = 0; j < TAM_POPULACAO; ++j) {
                for(int k = 0; k < NUM_VARIAVEIS; ++k) {
                    populacao[j][k] = populacaoTemp[j][k];
                }
            }

            bubbleSort();

        }

        
    }

    public double[][] getPopulacao() {
        return populacao;
    }

}
